{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第5阶段 第2讲：交互式可视化工具\n",
    "\n",
    "**课程时长**: 1.5小时  \n",
    "**难度等级**: ⭐⭐⭐⭐\n",
    "\n",
    "---\n",
    "\n",
    "## 📚 本讲学习目标\n",
    "\n",
    "1. 掌握Plotly交互式图表的创建与应用\n",
    "2. 学会使用Plotly Express快速构建交互式可视化\n",
    "3. 掌握Streamlit仪表板开发的核心技术\n",
    "4. 理解交互式组件的设计与实现\n",
    "5. 能够构建完整的交互式数据分析应用\n",
    "\n",
    "---\n",
    "\n",
    "## 📊 Excel vs Python 交互式可视化对比\n",
    "\n",
    "| 功能对比 | Excel | Python (Plotly + Streamlit) |\n",
    "|---------|-------|-----------------------------|\n",
    "| 交互性 | 有限(切片器、筛选器) | 强大(缩放、悬停、点击、动画) |\n",
    "| 动态更新 | 需要刷新数据透视表 | 实时自动更新 |\n",
    "| 图表类型 | 20+种基础图表 | 100+种专业图表 |\n",
    "| 仪表板 | Power BI集成 | Streamlit/Dash独立应用 |\n",
    "| 部署分享 | 文件共享或SharePoint | Web应用(可公开访问) |\n",
    "| 大数据处理 | <100万行 | 千万级数据无压力 |\n",
    "| 学习曲线 | 低 | 中等 |\n",
    "| 成本 | Office订阅 | 开源免费 |\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1️⃣ 环境准备与库安装\n",
    "\n",
    "### 1.1 安装必要的库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 安装所需库(首次运行时执行)\n",
    "# !pip install plotly pandas numpy streamlit\n",
    "\n",
    "# 导入基础库\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import plotly.express as px\n",
    "import plotly.graph_objects as go\n",
    "from plotly.subplots import make_subplots\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')\n",
    "\n",
    "print(\"✅ 库导入成功!\")\n",
    "print(f\"Plotly版本: {px.__version__ if hasattr(px, '__version__') else '已安装'}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 准备示例数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建销售数据集\n",
    "np.random.seed(42)\n",
    "dates = pd.date_range('2023-01-01', '2024-12-31', freq='D')\n",
    "sales_data = pd.DataFrame({\n",
    "    '日期': dates,\n",
    "    '销售额': np.random.randint(5000, 20000, len(dates)) + \n",
    "              np.sin(np.arange(len(dates)) * 2 * np.pi / 365) * 3000,\n",
    "    '订单量': np.random.randint(50, 200, len(dates)),\n",
    "    '地区': np.random.choice(['华东', '华南', '华北', '西南'], len(dates)),\n",
    "    '产品类别': np.random.choice(['电子产品', '服装', '食品', '家居'], len(dates)),\n",
    "    '客户类型': np.random.choice(['新客户', '老客户'], len(dates), p=[0.3, 0.7])\n",
    "})\n",
    "\n",
    "# 创建员工绩效数据\n",
    "employee_data = pd.DataFrame({\n",
    "    '姓名': [f'员工{i}' for i in range(1, 51)],\n",
    "    '部门': np.random.choice(['销售', '技术', '市场', '运营'], 50),\n",
    "    '销售额': np.random.randint(50000, 500000, 50),\n",
    "    '客户数': np.random.randint(10, 100, 50),\n",
    "    '满意度': np.random.uniform(3.5, 5.0, 50)\n",
    "})\n",
    "\n",
    "print(\"📊 示例数据集创建完成!\")\n",
    "print(f\"\\n销售数据: {sales_data.shape[0]}条记录\")\n",
    "print(f\"员工数据: {employee_data.shape[0]}条记录\")\n",
    "sales_data.head(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 2️⃣ Plotly Express 快速入门\n",
    "\n",
    "### 2.1 基础折线图 - 时间序列可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建基础交互式折线图\n",
    "fig = px.line(\n",
    "    sales_data, \n",
    "    x='日期', \n",
    "    y='销售额',\n",
    "    title='📈 2023-2024年销售额趋势(交互式)',\n",
    "    labels={'销售额': '销售额(元)', '日期': '日期'}\n",
    ")\n",
    "\n",
    "# 添加样式\n",
    "fig.update_traces(\n",
    "    line_color='#1f77b4',\n",
    "    line_width=2,\n",
    "    hovertemplate='<b>日期</b>: %{x}<br><b>销售额</b>: ¥%{y:,.0f}<extra></extra>'\n",
    ")\n",
    "\n",
    "fig.update_layout(\n",
    "    hovermode='x unified',\n",
    "    template='plotly_white',\n",
    "    height=400\n",
    ")\n",
    "\n",
    "fig.show()\n",
    "\n",
    "print(\"💡 交互技巧:\")\n",
    "print(\"  - 鼠标悬停查看详细数据\")\n",
    "print(\"  - 双击图例显示/隐藏数据系列\")\n",
    "print(\"  - 拖拽选择区域进行缩放\")\n",
    "print(\"  - 双击图表重置视图\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 分组折线图 - 多维度对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 按地区聚合数据\n",
    "region_sales = sales_data.groupby(['日期', '地区'])['销售额'].sum().reset_index()\n",
    "\n",
    "# 创建分组折线图\n",
    "fig = px.line(\n",
    "    region_sales,\n",
    "    x='日期',\n",
    "    y='销售额',\n",
    "    color='地区',\n",
    "    title='🗺️ 各地区销售额趋势对比',\n",
    "    labels={'销售额': '销售额(元)', '日期': '日期', '地区': '销售地区'}\n",
    ")\n",
    "\n",
    "fig.update_traces(\n",
    "    mode='lines',\n",
    "    line_width=2,\n",
    "    hovertemplate='<b>%{fullData.name}</b><br>日期: %{x}<br>销售额: ¥%{y:,.0f}<extra></extra>'\n",
    ")\n",
    "\n",
    "fig.update_layout(\n",
    "    hovermode='x unified',\n",
    "    template='plotly_white',\n",
    "    legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1),\n",
    "    height=400\n",
    ")\n",
    "\n",
    "fig.show()\n",
    "\n",
    "print(\"\\n📊 业务洞察:\")\n",
    "for region in region_sales['地区'].unique():\n",
    "    region_total = region_sales[region_sales['地区']==region]['销售额'].sum()\n",
    "    print(f\"  {region}: 总销售额 ¥{region_total:,.0f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3 交互式柱状图 - 带动画效果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 按产品类别统计销售额\n",
    "category_sales = sales_data.groupby('产品类别').agg({\n",
    "    '销售额': 'sum',\n",
    "    '订单量': 'sum'\n",
    "}).reset_index()\n",
    "\n",
    "category_sales = category_sales.sort_values('销售额', ascending=True)\n",
    "\n",
    "# 创建水平柱状图\n",
    "fig = px.bar(\n",
    "    category_sales,\n",
    "    x='销售额',\n",
    "    y='产品类别',\n",
    "    orientation='h',\n",
    "    title='🛒 各产品类别销售额对比',\n",
    "    text='销售额',\n",
    "    color='销售额',\n",
    "    color_continuous_scale='Blues'\n",
    ")\n",
    "\n",
    "fig.update_traces(\n",
    "    texttemplate='¥%{text:,.0f}',\n",
    "    textposition='outside',\n",
    "    hovertemplate='<b>%{y}</b><br>销售额: ¥%{x:,.0f}<br>订单量: %{customdata[0]:,}<extra></extra>',\n",
    "    customdata=category_sales[['订单量']]\n",
    ")\n",
    "\n",
    "fig.update_layout(\n",
    "    showlegend=False,\n",
    "    template='plotly_white',\n",
    "    height=400,\n",
    "    xaxis_title='销售额(元)',\n",
    "    yaxis_title=''\n",
    ")\n",
    "\n",
    "fig.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.4 散点图 - 气泡图展示三维数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建气泡图\n",
    "fig = px.scatter(\n",
    "    employee_data,\n",
    "    x='客户数',\n",
    "    y='销售额',\n",
    "    size='满意度',\n",
    "    color='部门',\n",
    "    hover_name='姓名',\n",
    "    title='👥 员工绩效分析(气泡大小代表满意度)',\n",
    "    labels={'客户数': '客户数量', '销售额': '销售额(元)', '部门': '所属部门'},\n",
    "    size_max=30\n",
    ")\n",
    "\n",
    "fig.update_traces(\n",
    "    marker=dict(line=dict(width=1, color='white')),\n",
    "    hovertemplate='<b>%{hovertext}</b><br>' +\n",
    "                  '客户数: %{x}<br>' +\n",
    "                  '销售额: ¥%{y:,.0f}<br>' +\n",
    "                  '满意度: %{marker.size:.2f}⭐<extra></extra>'\n",
    ")\n",
    "\n",
    "fig.update_layout(\n",
    "    template='plotly_white',\n",
    "    height=500,\n",
    "    legend=dict(title='部门', orientation='v', yanchor='top', y=1, xanchor='left', x=1.02)\n",
    ")\n",
    "\n",
    "fig.show()\n",
    "\n",
    "print(\"\\n🎯 分析维度:\")\n",
    "print(\"  X轴: 客户数量(越多越好)\")\n",
    "print(\"  Y轴: 销售额(越高越好)\")\n",
    "print(\"  气泡大小: 客户满意度(越大越好)\")\n",
    "print(\"  颜色: 部门分类\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 3️⃣ Plotly Graph Objects 高级定制\n",
    "\n",
    "### 3.1 创建复合图表 - 双Y轴"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 按月聚合数据\n",
    "sales_data['年月'] = sales_data['日期'].dt.to_period('M').astype(str)\n",
    "monthly_data = sales_data.groupby('年月').agg({\n",
    "    '销售额': 'sum',\n",
    "    '订单量': 'sum'\n",
    "}).reset_index()\n",
    "\n",
    "# 创建图形对象\n",
    "fig = go.Figure()\n",
    "\n",
    "# 添加柱状图(销售额)\n",
    "fig.add_trace(go.Bar(\n",
    "    x=monthly_data['年月'],\n",
    "    y=monthly_data['销售额'],\n",
    "    name='销售额',\n",
    "    marker_color='lightblue',\n",
    "    yaxis='y',\n",
    "    hovertemplate='<b>%{x}</b><br>销售额: ¥%{y:,.0f}<extra></extra>'\n",
    "))\n",
    "\n",
    "# 添加折线图(订单量)\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=monthly_data['年月'],\n",
    "    y=monthly_data['订单量'],\n",
    "    name='订单量',\n",
    "    mode='lines+markers',\n",
    "    line=dict(color='red', width=3),\n",
    "    marker=dict(size=8),\n",
    "    yaxis='y2',\n",
    "    hovertemplate='<b>%{x}</b><br>订单量: %{y:,}<extra></extra>'\n",
    "))\n",
    "\n",
    "# 设置双Y轴布局\n",
    "fig.update_layout(\n",
    "    title='📊 月度销售额与订单量趋势(双Y轴)',\n",
    "    xaxis=dict(title='月份'),\n",
    "    yaxis=dict(\n",
    "        title='销售额(元)',\n",
    "        titlefont=dict(color='blue'),\n",
    "        tickfont=dict(color='blue')\n",
    "    ),\n",
    "    yaxis2=dict(\n",
    "        title='订单量',\n",
    "        titlefont=dict(color='red'),\n",
    "        tickfont=dict(color='red'),\n",
    "        overlaying='y',\n",
    "        side='right'\n",
    "    ),\n",
    "    template='plotly_white',\n",
    "    hovermode='x unified',\n",
    "    height=450,\n",
    "    legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1)\n",
    ")\n",
    "\n",
    "fig.show()\n",
    "\n",
    "print(\"\\n💡 双Y轴适用场景:\")\n",
    "print(\"  ✓ 两个指标单位不同(如金额vs数量)\")\n",
    "print(\"  ✓ 两个指标数量级差异大\")\n",
    "print(\"  ✓ 需要同时观察两个指标的趋势\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 子图布局 - 创建仪表板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建2x2子图布局\n",
    "fig = make_subplots(\n",
    "    rows=2, cols=2,\n",
    "    subplot_titles=('销售额趋势', '地区分布', '产品类别占比', '客户类型对比'),\n",
    "    specs=[\n",
    "        [{'type': 'scatter'}, {'type': 'bar'}],\n",
    "        [{'type': 'pie'}, {'type': 'bar'}]\n",
    "    ],\n",
    "    vertical_spacing=0.12,\n",
    "    horizontal_spacing=0.1\n",
    ")\n",
    "\n",
    "# 子图1: 销售额趋势(按周聚合)\n",
    "weekly_sales = sales_data.groupby(sales_data['日期'].dt.to_period('W'))['销售额'].sum()\n",
    "fig.add_trace(\n",
    "    go.Scatter(\n",
    "        x=[str(p) for p in weekly_sales.index],\n",
    "        y=weekly_sales.values,\n",
    "        mode='lines',\n",
    "        line=dict(color='blue', width=2),\n",
    "        name='周销售额'\n",
    "    ),\n",
    "    row=1, col=1\n",
    ")\n",
    "\n",
    "# 子图2: 地区销售额\n",
    "region_total = sales_data.groupby('地区')['销售额'].sum().sort_values(ascending=True)\n",
    "fig.add_trace(\n",
    "    go.Bar(\n",
    "        x=region_total.values,\n",
    "        y=region_total.index,\n",
    "        orientation='h',\n",
    "        marker_color='lightgreen',\n",
    "        name='地区销售额'\n",
    "    ),\n",
    "    row=1, col=2\n",
    ")\n",
    "\n",
    "# 子图3: 产品类别占比\n",
    "category_total = sales_data.groupby('产品类别')['销售额'].sum()\n",
    "fig.add_trace(\n",
    "    go.Pie(\n",
    "        labels=category_total.index,\n",
    "        values=category_total.values,\n",
    "        hole=0.3,\n",
    "        name='产品占比'\n",
    "    ),\n",
    "    row=2, col=1\n",
    ")\n",
    "\n",
    "# 子图4: 客户类型销售额\n",
    "customer_total = sales_data.groupby('客户类型')['销售额'].sum()\n",
    "fig.add_trace(\n",
    "    go.Bar(\n",
    "        x=customer_total.index,\n",
    "        y=customer_total.values,\n",
    "        marker_color=['#FF6B6B', '#4ECDC4'],\n",
    "        name='客户类型'\n",
    "    ),\n",
    "    row=2, col=2\n",
    ")\n",
    "\n",
    "# 更新布局\n",
    "fig.update_layout(\n",
    "    title_text='📊 销售数据综合仪表板',\n",
    "    showlegend=False,\n",
    "    template='plotly_white',\n",
    "    height=700\n",
    ")\n",
    "\n",
    "# 隐藏第一个子图的X轴标签(数据太多)\n",
    "fig.update_xaxes(showticklabels=False, row=1, col=1)\n",
    "\n",
    "fig.show()\n",
    "\n",
    "print(\"\\n🎨 仪表板设计原则:\")\n",
    "print(\"  1. 信息层次清晰(重要指标放左上)\")\n",
    "print(\"  2. 图表类型多样(避免单调)\")\n",
    "print(\"  3. 色彩协调统一\")\n",
    "print(\"  4. 留白适当(不过度拥挤)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3 添加注释和形状"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算每日平均销售额\n",
    "daily_avg = sales_data.groupby('日期')['销售额'].mean().reset_index()\n",
    "\n",
    "# 找出最高和最低销售额的日期\n",
    "max_idx = daily_avg['销售额'].idxmax()\n",
    "min_idx = daily_avg['销售额'].idxmin()\n",
    "\n",
    "# 创建图表\n",
    "fig = go.Figure()\n",
    "\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=daily_avg['日期'],\n",
    "    y=daily_avg['销售额'],\n",
    "    mode='lines',\n",
    "    line=dict(color='steelblue', width=2),\n",
    "    name='日均销售额'\n",
    "))\n",
    "\n",
    "# 添加平均线\n",
    "avg_value = daily_avg['销售额'].mean()\n",
    "fig.add_hline(\n",
    "    y=avg_value,\n",
    "    line_dash='dash',\n",
    "    line_color='gray',\n",
    "    annotation_text=f'平均值: ¥{avg_value:,.0f}',\n",
    "    annotation_position='right'\n",
    ")\n",
    "\n",
    "# 添加最高点注释\n",
    "fig.add_annotation(\n",
    "    x=daily_avg.loc[max_idx, '日期'],\n",
    "    y=daily_avg.loc[max_idx, '销售额'],\n",
    "    text=f\"📈 最高<br>¥{daily_avg.loc[max_idx, '销售额']:,.0f}\",\n",
    "    showarrow=True,\n",
    "    arrowhead=2,\n",
    "    arrowcolor='green',\n",
    "    bgcolor='lightgreen',\n",
    "    bordercolor='green',\n",
    "    borderwidth=2,\n",
    "    font=dict(color='darkgreen')\n",
    ")\n",
    "\n",
    "# 添加最低点注释\n",
    "fig.add_annotation(\n",
    "    x=daily_avg.loc[min_idx, '日期'],\n",
    "    y=daily_avg.loc[min_idx, '销售额'],\n",
    "    text=f\"📉 最低<br>¥{daily_avg.loc[min_idx, '销售额']:,.0f}\",\n",
    "    showarrow=True,\n",
    "    arrowhead=2,\n",
    "    arrowcolor='red',\n",
    "    bgcolor='lightcoral',\n",
    "    bordercolor='red',\n",
    "    borderwidth=2,\n",
    "    font=dict(color='darkred')\n",
    ")\n",
    "\n",
    "# 添加矩形区域(标注重要时段)\n",
    "fig.add_vrect(\n",
    "    x0='2024-10-01', x1='2024-12-31',\n",
    "    fillcolor='yellow',\n",
    "    opacity=0.1,\n",
    "    line_width=0,\n",
    "    annotation_text='Q4旺季',\n",
    "    annotation_position='top left'\n",
    ")\n",
    "\n",
    "fig.update_layout(\n",
    "    title='📊 销售额趋势分析(带注释)',\n",
    "    xaxis_title='日期',\n",
    "    yaxis_title='销售额(元)',\n",
    "    template='plotly_white',\n",
    "    hovermode='x unified',\n",
    "    height=450,\n",
    "    showlegend=False\n",
    ")\n",
    "\n",
    "fig.show()\n",
    "\n",
    "print(\"\\n🎯 注释使用技巧:\")\n",
    "print(\"  ✓ 标注关键数据点\")\n",
    "print(\"  ✓ 添加参考线(如平均值、目标值)\")\n",
    "print(\"  ✓ 高亮重要时段\")\n",
    "print(\"  ✓ 使用颜色区分正负信息\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.4 动画图表 - 时间序列动画"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 准备动画数据(按月按地区)\n",
    "animation_data = sales_data.copy()\n",
    "animation_data['年月'] = animation_data['日期'].dt.to_period('M').astype(str)\n",
    "\n",
    "monthly_region = animation_data.groupby(['年月', '地区']).agg({\n",
    "    '销售额': 'sum',\n",
    "    '订单量': 'sum'\n",
    "}).reset_index()\n",
    "\n",
    "# 创建动画柱状图\n",
    "fig = px.bar(\n",
    "    monthly_region,\n",
    "    x='地区',\n",
    "    y='销售额',\n",
    "    color='地区',\n",
    "    animation_frame='年月',\n",
    "    animation_group='地区',\n",
    "    range_y=[0, monthly_region['销售额'].max() * 1.1],\n",
    "    title='🎬 各地区月度销售额变化动画',\n",
    "    labels={'销售额': '销售额(元)', '地区': '销售地区'}\n",
    ")\n",
    "\n",
    "fig.update_traces(\n",
    "    texttemplate='¥%{y:,.0f}',\n",
    "    textposition='outside'\n",
    ")\n",
    "\n",
    "fig.update_layout(\n",
    "    template='plotly_white',\n",
    "    height=500,\n",
    "    showlegend=False,\n",
    "    updatemenus=[dict(\n",
    "        type='buttons',\n",
    "        showactive=False,\n",
    "        buttons=[\n",
    "            dict(label='▶️ 播放', method='animate', args=[None, {'frame': {'duration': 500}}]),\n",
    "            dict(label='⏸️ 暂停', method='animate', args=[[None], {'frame': {'duration': 0}, 'mode': 'immediate'}])\n",
    "        ],\n",
    "        x=0.1, y=1.15\n",
    "    )]\n",
    ")\n",
    "\n",
    "fig.show()\n",
    "\n",
    "print(\"\\n🎥 动画图表应用场景:\")\n",
    "print(\"  • 展示数据随时间的变化\")\n",
    "print(\"  • 多维度数据的动态对比\")\n",
    "print(\"  • 汇报演示中的视觉冲击\")\n",
    "print(\"  • 社交媒体内容传播\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 4️⃣ Streamlit 仪表板开发\n",
    "\n",
    "### 4.1 Streamlit 基础概念\n",
    "\n",
    "**Streamlit是什么?**\n",
    "- 纯Python的Web应用框架\n",
    "- 无需HTML/CSS/JavaScript知识\n",
    "- 实时更新,代码改动即刻生效\n",
    "- 内置常用交互组件\n",
    "\n",
    "**核心优势:**\n",
    "- 🚀 极快的开发速度(几十行代码即可构建应用)\n",
    "- 🎨 美观的默认样式\n",
    "- 📱 自适应响应式设计\n",
    "- 🔄 自动缓存机制"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2 创建第一个Streamlit应用\n",
    "\n",
    "下面的代码需要保存为独立的`.py`文件运行:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将以下代码保存为 app_basic.py,然后在终端运行: streamlit run app_basic.py\n",
    "\n",
    "streamlit_basic_code = '''\n",
    "import streamlit as st\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import plotly.express as px\n",
    "\n",
    "# 页面配置\n",
    "st.set_page_config(\n",
    "    page_title=\"销售数据分析仪表板\",\n",
    "    page_icon=\"📊\",\n",
    "    layout=\"wide\"\n",
    ")\n",
    "\n",
    "# 标题\n",
    "st.title(\"📊 销售数据分析仪表板\")\n",
    "st.markdown(\"---\")\n",
    "\n",
    "# 侧边栏\n",
    "st.sidebar.header(\"筛选条件\")\n",
    "\n",
    "# 生成示例数据\n",
    "@st.cache_data\n",
    "def load_data():\n",
    "    dates = pd.date_range('2023-01-01', '2024-12-31', freq='D')\n",
    "    data = pd.DataFrame({\n",
    "        '日期': dates,\n",
    "        '销售额': np.random.randint(5000, 20000, len(dates)),\n",
    "        '订单量': np.random.randint(50, 200, len(dates)),\n",
    "        '地区': np.random.choice(['华东', '华南', '华北', '西南'], len(dates)),\n",
    "        '产品类别': np.random.choice(['电子产品', '服装', '食品', '家居'], len(dates))\n",
    "    })\n",
    "    return data\n",
    "\n",
    "data = load_data()\n",
    "\n",
    "# 侧边栏筛选\n",
    "selected_region = st.sidebar.multiselect(\n",
    "    \"选择地区\",\n",
    "    options=data['地区'].unique(),\n",
    "    default=data['地区'].unique()\n",
    ")\n",
    "\n",
    "selected_category = st.sidebar.multiselect(\n",
    "    \"选择产品类别\",\n",
    "    options=data['产品类别'].unique(),\n",
    "    default=data['产品类别'].unique()\n",
    ")\n",
    "\n",
    "# 数据筛选\n",
    "filtered_data = data[\n",
    "    (data['地区'].isin(selected_region)) & \n",
    "    (data['产品类别'].isin(selected_category))\n",
    "]\n",
    "\n",
    "# KPI指标\n",
    "col1, col2, col3, col4 = st.columns(4)\n",
    "\n",
    "with col1:\n",
    "    st.metric(\n",
    "        label=\"总销售额\",\n",
    "        value=f\"¥{filtered_data['销售额'].sum():,.0f}\",\n",
    "        delta=f\"{filtered_data['销售额'].sum() / data['销售额'].sum() * 100:.1f}%\"\n",
    "    )\n",
    "\n",
    "with col2:\n",
    "    st.metric(\n",
    "        label=\"总订单量\",\n",
    "        value=f\"{filtered_data['订单量'].sum():,}\",\n",
    "        delta=f\"{len(filtered_data)}\"\n",
    "    )\n",
    "\n",
    "with col3:\n",
    "    st.metric(\n",
    "        label=\"平均客单价\",\n",
    "        value=f\"¥{filtered_data['销售额'].sum() / filtered_data['订单量'].sum():.0f}\"\n",
    "    )\n",
    "\n",
    "with col4:\n",
    "    st.metric(\n",
    "        label=\"数据天数\",\n",
    "        value=f\"{len(filtered_data)}天\"\n",
    "    )\n",
    "\n",
    "st.markdown(\"---\")\n",
    "\n",
    "# 图表展示\n",
    "col_left, col_right = st.columns(2)\n",
    "\n",
    "with col_left:\n",
    "    st.subheader(\"📈 销售额趋势\")\n",
    "    fig1 = px.line(\n",
    "        filtered_data,\n",
    "        x='日期',\n",
    "        y='销售额',\n",
    "        title='日销售额趋势'\n",
    "    )\n",
    "    st.plotly_chart(fig1, use_container_width=True)\n",
    "\n",
    "with col_right:\n",
    "    st.subheader(\"🗺️ 地区分布\")\n",
    "    region_data = filtered_data.groupby('地区')['销售额'].sum().reset_index()\n",
    "    fig2 = px.pie(\n",
    "        region_data,\n",
    "        values='销售额',\n",
    "        names='地区',\n",
    "        title='各地区销售额占比'\n",
    "    )\n",
    "    st.plotly_chart(fig2, use_container_width=True)\n",
    "\n",
    "# 数据表格\n",
    "st.subheader(\"📋 原始数据\")\n",
    "st.dataframe(filtered_data.head(100), use_container_width=True)\n",
    "'''\n",
    "\n",
    "print(\"📝 Streamlit应用代码已生成!\")\n",
    "print(\"\\n使用步骤:\")\n",
    "print(\"1. 将上述代码复制到 app_basic.py 文件\")\n",
    "print(\"2. 在终端运行: streamlit run app_basic.py\")\n",
    "print(\"3. 浏览器会自动打开应用\")\n",
    "print(\"\\n代码已保存在变量 streamlit_basic_code 中\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.3 Streamlit 核心组件\n",
    "\n",
    "#### 布局组件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "streamlit_layout_code = '''\n",
    "import streamlit as st\n",
    "\n",
    "# 1. 列布局\n",
    "col1, col2, col3 = st.columns([1, 2, 1])  # 比例为1:2:1\n",
    "with col1:\n",
    "    st.write(\"左侧列\")\n",
    "with col2:\n",
    "    st.write(\"中间列(宽度是其他列的2倍)\")\n",
    "with col3:\n",
    "    st.write(\"右侧列\")\n",
    "\n",
    "# 2. 侧边栏\n",
    "with st.sidebar:\n",
    "    st.header(\"侧边栏\")\n",
    "    user_input = st.text_input(\"输入内容\")\n",
    "\n",
    "# 3. 选项卡\n",
    "tab1, tab2, tab3 = st.tabs([\"Tab 1\", \"Tab 2\", \"Tab 3\"])\n",
    "with tab1:\n",
    "    st.write(\"第一个选项卡的内容\")\n",
    "with tab2:\n",
    "    st.write(\"第二个选项卡的内容\")\n",
    "\n",
    "# 4. 展开/折叠\n",
    "with st.expander(\"点击展开查看详情\"):\n",
    "    st.write(\"这里是详细内容\")\n",
    "\n",
    "# 5. 容器\n",
    "container = st.container()\n",
    "container.write(\"这是容器中的内容\")\n",
    "'''\n",
    "\n",
    "print(\"🎨 Streamlit布局组件:\")\n",
    "print(\"  • st.columns() - 创建列布局\")\n",
    "print(\"  • st.sidebar - 侧边栏\")\n",
    "print(\"  • st.tabs() - 选项卡\")\n",
    "print(\"  • st.expander() - 可折叠区域\")\n",
    "print(\"  • st.container() - 容器\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 交互组件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "streamlit_widgets_code = '''\n",
    "import streamlit as st\n",
    "import pandas as pd\n",
    "\n",
    "# 1. 按钮\n",
    "if st.button(\"点击我\"):\n",
    "    st.write(\"按钮被点击了!\")\n",
    "\n",
    "# 2. 复选框\n",
    "agree = st.checkbox(\"我同意条款\")\n",
    "if agree:\n",
    "    st.write(\"感谢您的同意!\")\n",
    "\n",
    "# 3. 单选按钮\n",
    "option = st.radio(\n",
    "    \"选择一个选项\",\n",
    "    [\"选项1\", \"选项2\", \"选项3\"]\n",
    ")\n",
    "\n",
    "# 4. 下拉选择框\n",
    "choice = st.selectbox(\n",
    "    \"请选择\",\n",
    "    [\"A\", \"B\", \"C\"]\n",
    ")\n",
    "\n",
    "# 5. 多选框\n",
    "options = st.multiselect(\n",
    "    \"选择多个\",\n",
    "    [\"选项1\", \"选项2\", \"选项3\"],\n",
    "    default=[\"选项1\"]\n",
    ")\n",
    "\n",
    "# 6. 滑块\n",
    "value = st.slider(\n",
    "    \"选择一个值\",\n",
    "    min_value=0,\n",
    "    max_value=100,\n",
    "    value=50,\n",
    "    step=5\n",
    ")\n",
    "\n",
    "# 7. 数值输入\n",
    "number = st.number_input(\n",
    "    \"输入数字\",\n",
    "    min_value=0,\n",
    "    max_value=100,\n",
    "    value=10\n",
    ")\n",
    "\n",
    "# 8. 文本输入\n",
    "text = st.text_input(\"输入文本\")\n",
    "\n",
    "# 9. 日期选择\n",
    "date = st.date_input(\"选择日期\")\n",
    "\n",
    "# 10. 文件上传\n",
    "uploaded_file = st.file_uploader(\"上传CSV文件\", type=[\"csv\"])\n",
    "if uploaded_file is not None:\n",
    "    df = pd.read_csv(uploaded_file)\n",
    "    st.write(df)\n",
    "'''\n",
    "\n",
    "print(\"🎛️ Streamlit交互组件:\")\n",
    "print(\"  • st.button() - 按钮\")\n",
    "print(\"  • st.checkbox() - 复选框\")\n",
    "print(\"  • st.radio() - 单选按钮\")\n",
    "print(\"  • st.selectbox() - 下拉选择\")\n",
    "print(\"  • st.multiselect() - 多选框\")\n",
    "print(\"  • st.slider() - 滑块\")\n",
    "print(\"  • st.number_input() - 数值输入\")\n",
    "print(\"  • st.text_input() - 文本输入\")\n",
    "print(\"  • st.date_input() - 日期选择\")\n",
    "print(\"  • st.file_uploader() - 文件上传\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.4 完整的销售分析仪表板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将以下代码保存为 app_dashboard.py\n",
    "\n",
    "streamlit_dashboard_code = '''\n",
    "import streamlit as st\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import plotly.express as px\n",
    "import plotly.graph_objects as go\n",
    "from datetime import datetime, timedelta\n",
    "\n",
    "# 页面配置\n",
    "st.set_page_config(\n",
    "    page_title=\"企业销售分析仪表板\",\n",
    "    page_icon=\"📊\",\n",
    "    layout=\"wide\",\n",
    "    initial_sidebar_state=\"expanded\"\n",
    ")\n",
    "\n",
    "# 自定义CSS样式\n",
    "st.markdown(\"\"\"\n",
    "    <style>\n",
    "    .big-font {\n",
    "        font-size:30px !important;\n",
    "        font-weight: bold;\n",
    "    }\n",
    "    .metric-card {\n",
    "        background-color: #f0f2f6;\n",
    "        padding: 20px;\n",
    "        border-radius: 10px;\n",
    "        box-shadow: 2px 2px 5px rgba(0,0,0,0.1);\n",
    "    }\n",
    "    </style>\n",
    "    \"\"\", unsafe_allow_html=True)\n",
    "\n",
    "# 标题\n",
    "st.markdown('<p class=\"big-font\">📊 企业销售分析仪表板</p>', unsafe_allow_html=True)\n",
    "st.markdown(\"实时监控销售数据,洞察业务趋势\")\n",
    "st.markdown(\"---\")\n",
    "\n",
    "# 缓存数据加载\n",
    "@st.cache_data\n",
    "def generate_data():\n",
    "    \"\"\"生成模拟销售数据\"\"\"\n",
    "    dates = pd.date_range('2023-01-01', '2024-12-31', freq='D')\n",
    "    np.random.seed(42)\n",
    "    \n",
    "    data = pd.DataFrame({\n",
    "        '日期': dates,\n",
    "        '销售额': np.random.randint(5000, 20000, len(dates)) + \n",
    "                  np.sin(np.arange(len(dates)) * 2 * np.pi / 365) * 3000,\n",
    "        '订单量': np.random.randint(50, 200, len(dates)),\n",
    "        '地区': np.random.choice(['华东', '华南', '华北', '西南'], len(dates)),\n",
    "        '产品类别': np.random.choice(['电子产品', '服装', '食品', '家居'], len(dates)),\n",
    "        '客户类型': np.random.choice(['新客户', '老客户'], len(dates), p=[0.3, 0.7]),\n",
    "        '销售人员': np.random.choice([f'员工{i}' for i in range(1, 21)], len(dates))\n",
    "    })\n",
    "    \n",
    "    data['客单价'] = data['销售额'] / data['订单量']\n",
    "    return data\n",
    "\n",
    "# 加载数据\n",
    "df = generate_data()\n",
    "\n",
    "# 侧边栏 - 筛选条件\n",
    "st.sidebar.header(\"🔍 筛选条件\")\n",
    "\n",
    "# 日期范围选择\n",
    "date_range = st.sidebar.date_input(\n",
    "    \"选择日期范围\",\n",
    "    value=(df['日期'].min(), df['日期'].max()),\n",
    "    min_value=df['日期'].min(),\n",
    "    max_value=df['日期'].max()\n",
    ")\n",
    "\n",
    "if len(date_range) == 2:\n",
    "    start_date, end_date = date_range\n",
    "    mask = (df['日期'] >= pd.Timestamp(start_date)) & (df['日期'] <= pd.Timestamp(end_date))\n",
    "    df_filtered = df[mask]\n",
    "else:\n",
    "    df_filtered = df\n",
    "\n",
    "# 地区筛选\n",
    "regions = st.sidebar.multiselect(\n",
    "    \"选择地区\",\n",
    "    options=df['地区'].unique(),\n",
    "    default=df['地区'].unique()\n",
    ")\n",
    "\n",
    "# 产品类别筛选\n",
    "categories = st.sidebar.multiselect(\n",
    "    \"选择产品类别\",\n",
    "    options=df['产品类别'].unique(),\n",
    "    default=df['产品类别'].unique()\n",
    ")\n",
    "\n",
    "# 客户类型筛选\n",
    "customer_types = st.sidebar.multiselect(\n",
    "    \"选择客户类型\",\n",
    "    options=df['客户类型'].unique(),\n",
    "    default=df['客户类型'].unique()\n",
    ")\n",
    "\n",
    "# 应用筛选\n",
    "df_filtered = df_filtered[\n",
    "    (df_filtered['地区'].isin(regions)) &\n",
    "    (df_filtered['产品类别'].isin(categories)) &\n",
    "    (df_filtered['客户类型'].isin(customer_types))\n",
    "]\n",
    "\n",
    "# 侧边栏 - 数据摘要\n",
    "st.sidebar.markdown(\"---\")\n",
    "st.sidebar.subheader(\"📊 数据摘要\")\n",
    "st.sidebar.write(f\"总记录数: {len(df_filtered):,}\")\n",
    "st.sidebar.write(f\"筛选后占比: {len(df_filtered)/len(df)*100:.1f}%\")\n",
    "\n",
    "# 主面板 - KPI指标卡片\n",
    "st.subheader(\"🎯 核心业务指标\")\n",
    "\n",
    "col1, col2, col3, col4, col5 = st.columns(5)\n",
    "\n",
    "total_sales = df_filtered['销售额'].sum()\n",
    "total_orders = df_filtered['订单量'].sum()\n",
    "avg_price = df_filtered['客单价'].mean()\n",
    "total_days = len(df_filtered['日期'].unique())\n",
    "avg_daily_sales = total_sales / total_days if total_days > 0 else 0\n",
    "\n",
    "with col1:\n",
    "    st.metric(\n",
    "        label=\"总销售额\",\n",
    "        value=f\"¥{total_sales:,.0f}\",\n",
    "        delta=f\"{total_sales/df['销售额'].sum()*100:.1f}%\"\n",
    "    )\n",
    "\n",
    "with col2:\n",
    "    st.metric(\n",
    "        label=\"总订单量\",\n",
    "        value=f\"{total_orders:,}\",\n",
    "        delta=f\"{total_orders/df['订单量'].sum()*100:.1f}%\"\n",
    "    )\n",
    "\n",
    "with col3:\n",
    "    st.metric(\n",
    "        label=\"平均客单价\",\n",
    "        value=f\"¥{avg_price:.0f}\",\n",
    "        delta=f\"{(avg_price - df['客单价'].mean()) / df['客单价'].mean() * 100:.1f}%\"\n",
    "    )\n",
    "\n",
    "with col4:\n",
    "    st.metric(\n",
    "        label=\"日均销售额\",\n",
    "        value=f\"¥{avg_daily_sales:,.0f}\"\n",
    "    )\n",
    "\n",
    "with col5:\n",
    "    st.metric(\n",
    "        label=\"统计天数\",\n",
    "        value=f\"{total_days}天\"\n",
    "    )\n",
    "\n",
    "st.markdown(\"---\")\n",
    "\n",
    "# 图表区域 - 第一行\n",
    "col_left, col_right = st.columns(2)\n",
    "\n",
    "with col_left:\n",
    "    st.subheader(\"📈 销售额趋势分析\")\n",
    "    \n",
    "    # 按日期聚合\n",
    "    daily_sales = df_filtered.groupby('日期').agg({\n",
    "        '销售额': 'sum',\n",
    "        '订单量': 'sum'\n",
    "    }).reset_index()\n",
    "    \n",
    "    fig1 = go.Figure()\n",
    "    \n",
    "    fig1.add_trace(go.Scatter(\n",
    "        x=daily_sales['日期'],\n",
    "        y=daily_sales['销售额'],\n",
    "        mode='lines',\n",
    "        name='销售额',\n",
    "        line=dict(color='#1f77b4', width=2),\n",
    "        fill='tozeroy',\n",
    "        fillcolor='rgba(31, 119, 180, 0.1)'\n",
    "    ))\n",
    "    \n",
    "    fig1.update_layout(\n",
    "        template='plotly_white',\n",
    "        height=350,\n",
    "        hovermode='x unified',\n",
    "        xaxis_title='日期',\n",
    "        yaxis_title='销售额(元)'\n",
    "    )\n",
    "    \n",
    "    st.plotly_chart(fig1, use_container_width=True)\n",
    "\n",
    "with col_right:\n",
    "    st.subheader(\"🗺️ 地区销售分布\")\n",
    "    \n",
    "    region_sales = df_filtered.groupby('地区')['销售额'].sum().reset_index()\n",
    "    region_sales = region_sales.sort_values('销售额', ascending=True)\n",
    "    \n",
    "    fig2 = px.bar(\n",
    "        region_sales,\n",
    "        x='销售额',\n",
    "        y='地区',\n",
    "        orientation='h',\n",
    "        color='销售额',\n",
    "        color_continuous_scale='Blues',\n",
    "        text='销售额'\n",
    "    )\n",
    "    \n",
    "    fig2.update_traces(\n",
    "        texttemplate='¥%{text:,.0f}',\n",
    "        textposition='outside'\n",
    "    )\n",
    "    \n",
    "    fig2.update_layout(\n",
    "        template='plotly_white',\n",
    "        height=350,\n",
    "        showlegend=False,\n",
    "        xaxis_title='销售额(元)',\n",
    "        yaxis_title=''\n",
    "    )\n",
    "    \n",
    "    st.plotly_chart(fig2, use_container_width=True)\n",
    "\n",
    "# 图表区域 - 第二行\n",
    "col_left2, col_right2 = st.columns(2)\n",
    "\n",
    "with col_left2:\n",
    "    st.subheader(\"🛒 产品类别占比\")\n",
    "    \n",
    "    category_sales = df_filtered.groupby('产品类别')['销售额'].sum().reset_index()\n",
    "    \n",
    "    fig3 = px.pie(\n",
    "        category_sales,\n",
    "        values='销售额',\n",
    "        names='产品类别',\n",
    "        hole=0.4,\n",
    "        color_discrete_sequence=px.colors.qualitative.Set3\n",
    "    )\n",
    "    \n",
    "    fig3.update_traces(\n",
    "        textposition='inside',\n",
    "        textinfo='percent+label'\n",
    "    )\n",
    "    \n",
    "    fig3.update_layout(\n",
    "        template='plotly_white',\n",
    "        height=350\n",
    "    )\n",
    "    \n",
    "    st.plotly_chart(fig3, use_container_width=True)\n",
    "\n",
    "with col_right2:\n",
    "    st.subheader(\"👥 客户类型对比\")\n",
    "    \n",
    "    customer_sales = df_filtered.groupby('客户类型').agg({\n",
    "        '销售额': 'sum',\n",
    "        '订单量': 'sum'\n",
    "    }).reset_index()\n",
    "    \n",
    "    fig4 = go.Figure()\n",
    "    \n",
    "    fig4.add_trace(go.Bar(\n",
    "        x=customer_sales['客户类型'],\n",
    "        y=customer_sales['销售额'],\n",
    "        name='销售额',\n",
    "        marker_color='lightblue',\n",
    "        text=customer_sales['销售额'],\n",
    "        texttemplate='¥%{text:,.0f}',\n",
    "        textposition='outside'\n",
    "    ))\n",
    "    \n",
    "    fig4.update_layout(\n",
    "        template='plotly_white',\n",
    "        height=350,\n",
    "        xaxis_title='',\n",
    "        yaxis_title='销售额(元)',\n",
    "        showlegend=False\n",
    "    )\n",
    "    \n",
    "    st.plotly_chart(fig4, use_container_width=True)\n",
    "\n",
    "# 选项卡 - 详细数据\n",
    "st.markdown(\"---\")\n",
    "st.subheader(\"📋 详细数据分析\")\n",
    "\n",
    "tab1, tab2, tab3 = st.tabs([\"原始数据\", \"地区分析\", \"产品分析\"])\n",
    "\n",
    "with tab1:\n",
    "    st.dataframe(\n",
    "        df_filtered.sort_values('日期', ascending=False).head(500),\n",
    "        use_container_width=True,\n",
    "        height=400\n",
    "    )\n",
    "    \n",
    "    # 下载按钮\n",
    "    csv = df_filtered.to_csv(index=False, encoding='utf-8-sig')\n",
    "    st.download_button(\n",
    "        label=\"📥 下载筛选后的数据(CSV)\",\n",
    "        data=csv,\n",
    "        file_name=f\"sales_data_{datetime.now().strftime('%Y%m%d')}.csv\",\n",
    "        mime=\"text/csv\"\n",
    "    )\n",
    "\n",
    "with tab2:\n",
    "    region_detail = df_filtered.groupby('地区').agg({\n",
    "        '销售额': ['sum', 'mean', 'count'],\n",
    "        '订单量': 'sum',\n",
    "        '客单价': 'mean'\n",
    "    }).round(2)\n",
    "    \n",
    "    region_detail.columns = ['总销售额', '平均销售额', '天数', '总订单量', '平均客单价']\n",
    "    region_detail = region_detail.sort_values('总销售额', ascending=False)\n",
    "    \n",
    "    st.dataframe(\n",
    "        region_detail.style.format({\n",
    "            '总销售额': '¥{:,.0f}',\n",
    "            '平均销售额': '¥{:,.0f}',\n",
    "            '总订单量': '{:,}',\n",
    "            '平均客单价': '¥{:.0f}'\n",
    "        }),\n",
    "        use_container_width=True\n",
    "    )\n",
    "\n",
    "with tab3:\n",
    "    category_detail = df_filtered.groupby('产品类别').agg({\n",
    "        '销售额': ['sum', 'mean', 'count'],\n",
    "        '订单量': 'sum',\n",
    "        '客单价': 'mean'\n",
    "    }).round(2)\n",
    "    \n",
    "    category_detail.columns = ['总销售额', '平均销售额', '天数', '总订单量', '平均客单价']\n",
    "    category_detail = category_detail.sort_values('总销售额', ascending=False)\n",
    "    \n",
    "    st.dataframe(\n",
    "        category_detail.style.format({\n",
    "            '总销售额': '¥{:,.0f}',\n",
    "            '平均销售额': '¥{:,.0f}',\n",
    "            '总订单量': '{:,}',\n",
    "            '平均客单价': '¥{:.0f}'\n",
    "        }),\n",
    "        use_container_width=True\n",
    "    )\n",
    "\n",
    "# 页脚\n",
    "st.markdown(\"---\")\n",
    "st.markdown(\n",
    "    \"<div style='text-align: center; color: gray;'>\" \n",
    "    \"📊 企业销售分析仪表板 | 数据更新时间: {}\" \n",
    "    \"</div>\".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S')),\n",
    "    unsafe_allow_html=True\n",
    ")\n",
    "'''\n",
    "\n",
    "print(\"✅ 完整仪表板代码已生成!\")\n",
    "print(\"\\n🎯 功能特性:\")\n",
    "print(\"  ✓ 多维度数据筛选\")\n",
    "print(\"  ✓ 5个核心KPI指标\")\n",
    "print(\"  ✓ 4个可视化图表\")\n",
    "print(\"  ✓ 3个数据分析选项卡\")\n",
    "print(\"  ✓ 数据下载功能\")\n",
    "print(\"  ✓ 响应式布局\")\n",
    "print(\"  ✓ 自定义CSS样式\")\n",
    "print(\"\\n💾 将代码保存为 app_dashboard.py\")\n",
    "print(\"🚀 运行命令: streamlit run app_dashboard.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.5 Streamlit 部署方案\n",
    "\n",
    "#### 方案1: Streamlit Cloud (推荐)\n",
    "\n",
    "**优点**: 完全免费,部署简单,自动更新\n",
    "\n",
    "**步骤**:\n",
    "1. 将代码推送到GitHub仓库\n",
    "2. 访问 https://streamlit.io/cloud\n",
    "3. 连接GitHub账号\n",
    "4. 选择仓库和主文件\n",
    "5. 点击Deploy\n",
    "\n",
    "#### 方案2: Heroku\n",
    "\n",
    "**步骤**:\n",
    "```bash\n",
    "# 创建必要文件\n",
    "# requirements.txt\n",
    "streamlit\n",
    "pandas\n",
    "numpy\n",
    "plotly\n",
    "\n",
    "# setup.sh\n",
    "mkdir -p ~/.streamlit/\n",
    "echo \"[server]\\n\\nheadless = true\\n\\nport = $PORT\\n\\nenableCORS = false\\n\\n\" > ~/.streamlit/config.toml\n",
    "\n",
    "# Procfile\n",
    "web: sh setup.sh && streamlit run app.py\n",
    "\n",
    "# 部署到Heroku\n",
    "heroku login\n",
    "heroku create your-app-name\n",
    "git push heroku main\n",
    "```\n",
    "\n",
    "#### 方案3: Docker容器化\n",
    "\n",
    "```dockerfile\n",
    "# Dockerfile\n",
    "FROM python:3.9-slim\n",
    "\n",
    "WORKDIR /app\n",
    "\n",
    "COPY requirements.txt .\n",
    "RUN pip install -r requirements.txt\n",
    "\n",
    "COPY . .\n",
    "\n",
    "EXPOSE 8501\n",
    "\n",
    "CMD [\"streamlit\", \"run\", \"app.py\", \"--server.port=8501\", \"--server.address=0.0.0.0\"]\n",
    "```\n",
    "\n",
    "```bash\n",
    "# 构建和运行\n",
    "docker build -t streamlit-app .\n",
    "docker run -p 8501:8501 streamlit-app\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 5️⃣ 高级技巧与最佳实践\n",
    "\n",
    "### 5.1 性能优化 - 缓存机制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "streamlit_cache_code = '''\n",
    "import streamlit as st\n",
    "import pandas as pd\n",
    "import time\n",
    "\n",
    "# 1. 缓存数据加载 (适用于数据不经常变化)\n",
    "@st.cache_data\n",
    "def load_data(file_path):\n",
    "    \"\"\"缓存数据读取,避免重复加载\"\"\"\n",
    "    time.sleep(2)  # 模拟耗时操作\n",
    "    df = pd.read_csv(file_path)\n",
    "    return df\n",
    "\n",
    "# 2. 缓存资源 (适用于数据库连接等)\n",
    "@st.cache_resource\n",
    "def get_database_connection():\n",
    "    \"\"\"缓存数据库连接对象\"\"\"\n",
    "    # connection = create_connection()\n",
    "    return connection\n",
    "\n",
    "# 3. 设置缓存过期时间\n",
    "@st.cache_data(ttl=600)  # 10分钟后过期\n",
    "def load_api_data():\n",
    "    \"\"\"加载API数据,10分钟后自动刷新\"\"\"\n",
    "    # data = fetch_from_api()\n",
    "    return data\n",
    "\n",
    "# 4. 清除缓存\n",
    "if st.button(\"清除缓存\"):\n",
    "    st.cache_data.clear()\n",
    "    st.success(\"缓存已清除!\")\n",
    "\n",
    "# 使用示例\n",
    "df = load_data(\"data.csv\")  # 首次加载需要2秒,后续瞬间完成\n",
    "st.write(df)\n",
    "'''\n",
    "\n",
    "print(\"⚡ Streamlit缓存机制:\")\n",
    "print(\"  • @st.cache_data - 缓存数据(DataFrame、列表等)\")\n",
    "print(\"  • @st.cache_resource - 缓存资源(数据库连接、模型等)\")\n",
    "print(\"  • ttl参数 - 设置缓存过期时间\")\n",
    "print(\"  • st.cache_data.clear() - 清除缓存\")\n",
    "print(\"\\n💡 何时使用缓存:\")\n",
    "print(\"  ✓ 加载大型数据集\")\n",
    "print(\"  ✓ 复杂的数据处理\")\n",
    "print(\"  ✓ API调用\")\n",
    "print(\"  ✓ 数据库查询\")\n",
    "print(\"  ✓ 机器学习模型加载\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.2 响应式设计技巧"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "streamlit_responsive_code = '''\n",
    "import streamlit as st\n",
    "\n",
    "# 1. 使用比例列布局\n",
    "col1, col2, col3 = st.columns([2, 3, 1])  # 不同宽度比例\n",
    "\n",
    "# 2. 使用容器实现模块化\n",
    "with st.container():\n",
    "    st.header(\"模块1\")\n",
    "    # 模块1的内容\n",
    "\n",
    "with st.container():\n",
    "    st.header(\"模块2\")\n",
    "    # 模块2的内容\n",
    "\n",
    "# 3. 动态调整图表高度\n",
    "import plotly.express as px\n",
    "import pandas as pd\n",
    "\n",
    "df = pd.DataFrame({...})\n",
    "fig = px.line(df, x='date', y='value')\n",
    "\n",
    "# 使用 use_container_width=True 让图表自适应容器宽度\n",
    "st.plotly_chart(fig, use_container_width=True)\n",
    "\n",
    "# 4. 使用expander节省空间\n",
    "with st.expander(\"点击查看详细设置\"):\n",
    "    option1 = st.checkbox(\"选项1\")\n",
    "    option2 = st.selectbox(\"选择\", [\"A\", \"B\", \"C\"])\n",
    "\n",
    "# 5. 侧边栏放置次要控件\n",
    "with st.sidebar:\n",
    "    st.header(\"设置\")\n",
    "    # 次要的筛选和配置选项\n",
    "'''\n",
    "\n",
    "print(\"📱 响应式设计原则:\")\n",
    "print(\"  1. 使用列布局而非固定宽度\")\n",
    "print(\"  2. 图表使用 use_container_width=True\")\n",
    "print(\"  3. 重要信息放主面板,次要信息放侧边栏\")\n",
    "print(\"  4. 使用expander折叠非关键内容\")\n",
    "print(\"  5. 避免过深的嵌套\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.3 状态管理 - Session State"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "streamlit_state_code = '''\n",
    "import streamlit as st\n",
    "\n",
    "# 初始化session state\n",
    "if 'counter' not in st.session_state:\n",
    "    st.session_state.counter = 0\n",
    "\n",
    "if 'user_data' not in st.session_state:\n",
    "    st.session_state.user_data = {}\n",
    "\n",
    "# 使用session state保持状态\n",
    "if st.button(\"增加计数\"):\n",
    "    st.session_state.counter += 1\n",
    "\n",
    "st.write(f\"当前计数: {st.session_state.counter}\")\n",
    "\n",
    "# 存储用户输入\n",
    "name = st.text_input(\"输入姓名\")\n",
    "if name:\n",
    "    st.session_state.user_data['name'] = name\n",
    "\n",
    "# 多页面状态共享\n",
    "if 'page' not in st.session_state:\n",
    "    st.session_state.page = 'home'\n",
    "\n",
    "if st.button(\"前往页面2\"):\n",
    "    st.session_state.page = 'page2'\n",
    "\n",
    "# 根据状态显示不同内容\n",
    "if st.session_state.page == 'home':\n",
    "    st.write(\"欢迎来到首页\")\n",
    "elif st.session_state.page == 'page2':\n",
    "    st.write(\"这是第二页\")\n",
    "'''\n",
    "\n",
    "print(\"🔄 Session State应用场景:\")\n",
    "print(\"  • 跨页面数据传递\")\n",
    "print(\"  • 表单多步骤流程\")\n",
    "print(\"  • 用户登录状态\")\n",
    "print(\"  • 临时数据存储\")\n",
    "print(\"  • 计数器和累积器\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 6️⃣ 实战案例: 销售预测仪表板\n",
    "\n",
    "### 6.1 功能需求\n",
    "\n",
    "1. 历史数据可视化\n",
    "2. 趋势预测(简单移动平均)\n",
    "3. 异常检测\n",
    "4. 导出预测报告\n",
    "\n",
    "### 6.2 完整代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将以下代码保存为 app_forecast.py\n",
    "\n",
    "forecast_app_code = '''\n",
    "import streamlit as st\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import plotly.graph_objects as go\n",
    "from datetime import datetime, timedelta\n",
    "\n",
    "st.set_page_config(page_title=\"销售预测仪表板\", page_icon=\"📈\", layout=\"wide\")\n",
    "\n",
    "st.title(\"📈 销售预测仪表板\")\n",
    "st.markdown(\"基于历史数据的销售趋势预测与异常检测\")\n",
    "st.markdown(\"---\")\n",
    "\n",
    "# 生成示例数据\n",
    "@st.cache_data\n",
    "def generate_sales_data():\n",
    "    dates = pd.date_range('2023-01-01', '2024-12-31', freq='D')\n",
    "    np.random.seed(42)\n",
    "    \n",
    "    # 基础趋势 + 季节性 + 随机噪声\n",
    "    trend = np.linspace(10000, 15000, len(dates))\n",
    "    seasonal = 2000 * np.sin(np.arange(len(dates)) * 2 * np.pi / 365)\n",
    "    noise = np.random.normal(0, 500, len(dates))\n",
    "    \n",
    "    sales = trend + seasonal + noise\n",
    "    \n",
    "    # 添加几个异常值\n",
    "    anomaly_indices = np.random.choice(len(dates), 10, replace=False)\n",
    "    sales[anomaly_indices] += np.random.choice([-5000, 5000], 10)\n",
    "    \n",
    "    df = pd.DataFrame({\n",
    "        '日期': dates,\n",
    "        '销售额': sales\n",
    "    })\n",
    "    \n",
    "    return df\n",
    "\n",
    "df = generate_sales_data()\n",
    "\n",
    "# 侧边栏配置\n",
    "st.sidebar.header(\"⚙️ 预测参数\")\n",
    "\n",
    "# 移动平均窗口\n",
    "ma_window = st.sidebar.slider(\n",
    "    \"移动平均窗口(天)\",\n",
    "    min_value=7,\n",
    "    max_value=90,\n",
    "    value=30,\n",
    "    step=7\n",
    ")\n",
    "\n",
    "# 预测天数\n",
    "forecast_days = st.sidebar.slider(\n",
    "    \"预测天数\",\n",
    "    min_value=7,\n",
    "    max_value=90,\n",
    "    value=30,\n",
    "    step=7\n",
    ")\n",
    "\n",
    "# 异常检测阈值\n",
    "anomaly_threshold = st.sidebar.slider(\n",
    "    \"异常检测标准差倍数\",\n",
    "    min_value=1.5,\n",
    "    max_value=3.5,\n",
    "    value=2.5,\n",
    "    step=0.5\n",
    ")\n",
    "\n",
    "# 计算移动平均\n",
    "df['移动平均'] = df['销售额'].rolling(window=ma_window).mean()\n",
    "\n",
    "# 异常检测\n",
    "df['滚动标准差'] = df['销售额'].rolling(window=ma_window).std()\n",
    "df['上界'] = df['移动平均'] + anomaly_threshold * df['滚动标准差']\n",
    "df['下界'] = df['移动平均'] - anomaly_threshold * df['滚动标准差']\n",
    "df['异常'] = (df['销售额'] > df['上界']) | (df['销售额'] < df['下界'])\n",
    "\n",
    "# 生成预测\n",
    "last_ma = df['移动平均'].iloc[-1]\n",
    "forecast_dates = pd.date_range(\n",
    "    df['日期'].iloc[-1] + timedelta(days=1),\n",
    "    periods=forecast_days,\n",
    "    freq='D'\n",
    ")\n",
    "\n",
    "# 简单预测: 使用最后的移动平均值 + 季节性模式\n",
    "forecast_values = []\n",
    "for i in range(forecast_days):\n",
    "    seasonal_component = 2000 * np.sin((len(df) + i) * 2 * np.pi / 365)\n",
    "    forecast_values.append(last_ma + seasonal_component)\n",
    "\n",
    "forecast_df = pd.DataFrame({\n",
    "    '日期': forecast_dates,\n",
    "    '预测销售额': forecast_values\n",
    "})\n",
    "\n",
    "# KPI指标\n",
    "col1, col2, col3, col4 = st.columns(4)\n",
    "\n",
    "with col1:\n",
    "    st.metric(\n",
    "        label=\"历史平均销售额\",\n",
    "        value=f\"¥{df['销售额'].mean():,.0f}\"\n",
    "    )\n",
    "\n",
    "with col2:\n",
    "    st.metric(\n",
    "        label=\"最近30天平均\",\n",
    "        value=f\"¥{df['销售额'].tail(30).mean():,.0f}\",\n",
    "        delta=f\"{(df['销售额'].tail(30).mean() - df['销售额'].mean()) / df['销售额'].mean() * 100:.1f}%\"\n",
    "    )\n",
    "\n",
    "with col3:\n",
    "    st.metric(\n",
    "        label=\"预测平均销售额\",\n",
    "        value=f\"¥{forecast_df['预测销售额'].mean():,.0f}\"\n",
    "    )\n",
    "\n",
    "with col4:\n",
    "    anomaly_count = df['异常'].sum()\n",
    "    st.metric(\n",
    "        label=\"检测到的异常天数\",\n",
    "        value=f\"{anomaly_count}天\",\n",
    "        delta=f\"{anomaly_count / len(df) * 100:.1f}%\"\n",
    "    )\n",
    "\n",
    "st.markdown(\"---\")\n",
    "\n",
    "# 主图表\n",
    "st.subheader(\"📊 历史数据与预测\")\n",
    "\n",
    "fig = go.Figure()\n",
    "\n",
    "# 历史销售额\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=df['日期'],\n",
    "    y=df['销售额'],\n",
    "    mode='lines',\n",
    "    name='实际销售额',\n",
    "    line=dict(color='lightgray', width=1)\n",
    "))\n",
    "\n",
    "# 移动平均\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=df['日期'],\n",
    "    y=df['移动平均'],\n",
    "    mode='lines',\n",
    "    name=f'{ma_window}天移动平均',\n",
    "    line=dict(color='blue', width=2)\n",
    "))\n",
    "\n",
    "# 异常点\n",
    "anomalies = df[df['异常']]\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=anomalies['日期'],\n",
    "    y=anomalies['销售额'],\n",
    "    mode='markers',\n",
    "    name='异常点',\n",
    "    marker=dict(color='red', size=10, symbol='x')\n",
    "))\n",
    "\n",
    "# 预测\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=forecast_df['日期'],\n",
    "    y=forecast_df['预测销售额'],\n",
    "    mode='lines',\n",
    "    name='预测销售额',\n",
    "    line=dict(color='green', width=2, dash='dash')\n",
    "))\n",
    "\n",
    "# 置信区间\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=df['日期'],\n",
    "    y=df['上界'],\n",
    "    mode='lines',\n",
    "    line=dict(width=0),\n",
    "    showlegend=False,\n",
    "    hoverinfo='skip'\n",
    "))\n",
    "\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=df['日期'],\n",
    "    y=df['下界'],\n",
    "    mode='lines',\n",
    "    fill='tonexty',\n",
    "    fillcolor='rgba(0,100,200,0.1)',\n",
    "    line=dict(width=0),\n",
    "    name='置信区间',\n",
    "    hoverinfo='skip'\n",
    "))\n",
    "\n",
    "fig.update_layout(\n",
    "    template='plotly_white',\n",
    "    hovermode='x unified',\n",
    "    height=500,\n",
    "    xaxis_title='日期',\n",
    "    yaxis_title='销售额(元)',\n",
    "    legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1)\n",
    ")\n",
    "\n",
    "st.plotly_chart(fig, use_container_width=True)\n",
    "\n",
    "# 详细分析\n",
    "col_left, col_right = st.columns(2)\n",
    "\n",
    "with col_left:\n",
    "    st.subheader(\"🔍 异常明细\")\n",
    "    if len(anomalies) > 0:\n",
    "        anomaly_detail = anomalies[['日期', '销售额', '移动平均']].copy()\n",
    "        anomaly_detail['偏离度'] = ((anomaly_detail['销售额'] - anomaly_detail['移动平均']) / \n",
    "                                   anomaly_detail['移动平均'] * 100)\n",
    "        anomaly_detail = anomaly_detail.sort_values('日期', ascending=False)\n",
    "        \n",
    "        st.dataframe(\n",
    "            anomaly_detail.style.format({\n",
    "                '销售额': '¥{:,.0f}',\n",
    "                '移动平均': '¥{:,.0f}',\n",
    "                '偏离度': '{:.1f}%'\n",
    "            }),\n",
    "            use_container_width=True,\n",
    "            height=300\n",
    "        )\n",
    "    else:\n",
    "        st.info(\"未检测到异常数据\")\n",
    "\n",
    "with col_right:\n",
    "    st.subheader(\"📅 预测数据\")\n",
    "    st.dataframe(\n",
    "        forecast_df.style.format({'预测销售额': '¥{:,.0f}'}),\n",
    "        use_container_width=True,\n",
    "        height=300\n",
    "    )\n",
    "\n",
    "# 下载报告\n",
    "st.markdown(\"---\")\n",
    "st.subheader(\"📥 导出报告\")\n",
    "\n",
    "col_download1, col_download2 = st.columns(2)\n",
    "\n",
    "with col_download1:\n",
    "    # 导出历史数据\n",
    "    csv_historical = df.to_csv(index=False, encoding='utf-8-sig')\n",
    "    st.download_button(\n",
    "        label=\"下载历史数据(CSV)\",\n",
    "        data=csv_historical,\n",
    "        file_name=f\"historical_data_{datetime.now().strftime('%Y%m%d')}.csv\",\n",
    "        mime=\"text/csv\"\n",
    "    )\n",
    "\n",
    "with col_download2:\n",
    "    # 导出预测数据\n",
    "    csv_forecast = forecast_df.to_csv(index=False, encoding='utf-8-sig')\n",
    "    st.download_button(\n",
    "        label=\"下载预测数据(CSV)\",\n",
    "        data=csv_forecast,\n",
    "        file_name=f\"forecast_data_{datetime.now().strftime('%Y%m%d')}.csv\",\n",
    "        mime=\"text/csv\"\n",
    "    )\n",
    "\n",
    "# 页脚\n",
    "st.markdown(\"---\")\n",
    "st.markdown(\n",
    "    f\"<div style='text-align: center; color: gray;'>\"\n",
    "    f\"📈 销售预测仪表板 | 最后更新: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\"\n",
    "    f\"</div>\",\n",
    "    unsafe_allow_html=True\n",
    ")\n",
    "'''\n",
    "\n",
    "print(\"✅ 销售预测仪表板代码已生成!\")\n",
    "print(\"\\n🎯 核心功能:\")\n",
    "print(\"  ✓ 移动平均趋势分析\")\n",
    "print(\"  ✓ 基于统计的异常检测\")\n",
    "print(\"  ✓ 简单时间序列预测\")\n",
    "print(\"  ✓ 置信区间可视化\")\n",
    "print(\"  ✓ 异常明细报告\")\n",
    "print(\"  ✓ 数据导出功能\")\n",
    "print(\"\\n💾 保存文件: app_forecast.py\")\n",
    "print(\"🚀 运行: streamlit run app_forecast.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 📝 课堂作业\n",
    "\n",
    "### 作业1: Plotly交互图表实践 (⭐⭐)\n",
    "\n",
    "**要求**:\n",
    "1. 使用提供的员工绩效数据(employee_data)\n",
    "2. 创建一个气泡图,展示销售额、客户数、满意度三个维度\n",
    "3. 按部门用不同颜色区分\n",
    "4. 添加自定义悬停信息,包含员工姓名和所有指标\n",
    "5. 添加平均线标注\n",
    "\n",
    "**提示**:\n",
    "- 使用 px.scatter() 创建气泡图\n",
    "- size 参数控制气泡大小\n",
    "- hovertemplate 自定义悬停信息\n",
    "- add_hline() / add_vline() 添加参考线\n",
    "\n",
    "---\n",
    "\n",
    "### 作业2: Streamlit仪表板开发 (⭐⭐⭐⭐)\n",
    "\n",
    "**要求**:\n",
    "创建一个完整的数据分析仪表板,包含以下功能:\n",
    "\n",
    "1. **数据上传功能**\n",
    "   - 支持CSV文件上传\n",
    "   - 显示数据预览和基本信息\n",
    "\n",
    "2. **交互式筛选**\n",
    "   - 侧边栏放置筛选条件\n",
    "   - 至少3个筛选维度(如日期范围、类别、地区)\n",
    "\n",
    "3. **KPI指标卡片**\n",
    "   - 显示4-6个核心指标\n",
    "   - 使用st.metric()显示变化趋势\n",
    "\n",
    "4. **可视化图表**\n",
    "   - 至少包含3种不同类型的图表\n",
    "   - 使用Plotly创建交互式图表\n",
    "   - 合理使用列布局\n",
    "\n",
    "5. **数据导出**\n",
    "   - 支持下载筛选后的数据\n",
    "\n",
    "**提示**:\n",
    "- 参考课件中的 app_dashboard.py 代码\n",
    "- 使用 @st.cache_data 优化性能\n",
    "- 保存为独立的 .py 文件运行\n",
    "\n",
    "---\n",
    "\n",
    "### 作业3: 综合应用 - 产品销量分析仪表板 (⭐⭐⭐⭐⭐)\n",
    "\n",
    "**场景描述**:\n",
    "某电商公司需要一个产品销量分析仪表板,帮助产品经理实时监控各产品线的表现。\n",
    "\n",
    "**要求**:\n",
    "\n",
    "1. **数据准备**\n",
    "   - 生成或使用真实的产品销量数据\n",
    "   - 包含字段:日期、产品名称、产品类别、销量、销售额、地区\n",
    "\n",
    "2. **核心功能**\n",
    "   - 产品销量排行榜(Top 10)\n",
    "   - 类别占比分析(饼图/环形图)\n",
    "   - 销量趋势分析(时间序列折线图)\n",
    "   - 地区对比分析(柱状图)\n",
    "   - 产品关联分析(散点图或热力图)\n",
    "\n",
    "3. **高级特性**\n",
    "   - 支持动态筛选(日期、产品类别、地区)\n",
    "   - 同比/环比分析\n",
    "   - 预警功能(销量低于目标时高亮显示)\n",
    "   - 数据导出(Excel格式)\n",
    "\n",
    "4. **美化要求**\n",
    "   - 统一的配色方案\n",
    "   - 响应式布局\n",
    "   - 添加自定义CSS样式\n",
    "   - Logo和公司信息\n",
    "\n",
    "**加分项**:\n",
    "- 部署到Streamlit Cloud并分享链接\n",
    "- 添加用户登录功能\n",
    "- 集成数据库(SQLite/PostgreSQL)\n",
    "- 实时数据更新功能\n",
    "\n",
    "---\n",
    "\n",
    "## 📚 扩展学习资源\n",
    "\n",
    "### 官方文档\n",
    "- Plotly官方文档: https://plotly.com/python/\n",
    "- Streamlit官方文档: https://docs.streamlit.io/\n",
    "\n",
    "### 推荐教程\n",
    "- Plotly图表示例库: https://plotly.com/python/plotly-express/\n",
    "- Streamlit Gallery: https://streamlit.io/gallery\n",
    "\n",
    "### 进阶主题\n",
    "- Dash (更强大的仪表板框架)\n",
    "- Plotly Dash Callbacks (复杂交互)\n",
    "- Streamlit Components (自定义组件)\n",
    "\n",
    "---\n",
    "\n",
    "## 🎓 本讲小结\n",
    "\n",
    "通过本讲学习,你应该掌握:\n",
    "\n",
    "✅ Plotly Express快速创建交互式图表  \n",
    "✅ Plotly Graph Objects高级定制  \n",
    "✅ 动画图表和子图布局  \n",
    "✅ Streamlit核心组件和布局  \n",
    "✅ 完整仪表板的设计与开发  \n",
    "✅ 性能优化和部署方案  \n",
    "\n",
    "**下一讲预告**: 可视化综合项目 - 从0到1构建企业级数据分析平台\n",
    "\n",
    "---"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}